﻿#include "EasyIOCPServer.h"

#ifdef _WIN32

#include "CELLIOCP.hpp"
// #include "CELLSelectServer.h"
#include "CELLIOCPServer.h"
#include "CELLNetWork.hpp"

void EasyIOCPServer::Start(int nCELLServer)
{
	EasyTcpServer::Start<CELLIOCPServer>(nCELLServer);
}

// 处理网络消息
void EasyIOCPServer::OnRun(CELLThread* pthread)
{
	CELLIOCP iocp;
	iocp.loadAcceptEX(sockfd());
	iocp.create();
	iocp.reg(sockfd());
	// 接收新客户端时需要接收数据的缓冲区，理论上只需要下面这么大的空间
	// const int len = 2 * (sizeof(sockaddr_in) + 16);
	// 如果还要在接收连接的时候接收额外的数据就需要更大的空间，这里直接设置成了1024
	// 不需要客户端连接后立即发送数据的情况下是上面计算的len大小
	const int len = 1024;
	char buffer[len] = { 0 };
	IO_DATA_BASE ioData = { 0 };
	ioData.wsaBuff.buf = buffer;
	ioData.wsaBuff.len = len;
	// 
	IO_EVENT ioEvent;
	// 投递接收一个链接的任务
	iocp.postAccept(&ioData);
	time_t time;
	while (pthread->isRun())
	{
		time4msg();
		time = _time_event.getTime();
		if (time == -1)
		{
			time = INFINITE;
		}
		int ret = iocp.wait(ioEvent, time);
		if (ret < 0)
		{
			CELLLog_pError("EasyIOCPServer::OnRun error");
			pthread->Exit();
			break;
		}
		else if (ret == 0)
		{
			_time_event.process_timer();
			continue;
		}

		// 接受新连接
		if (IO_TYPE::ACCEPT == ioEvent.pIOData->iotype)
		{
			// 新客户端加入
			// CELLLog_Info("new client join sockfd=%d", (int)ioEvent.pIOData->sockfd);
			// 调用的是本类的IocpAccept客户端函数
			IocpAccept(ioData.sockfd);
			// 再次向IOCP投递接收新连接的任务
			/*
				错误记录：投递接收新连接任务如果放在IocpAccept之前会报很多错误
				!: 原因：投递出去的任务会直接完成，如果超出了最大限制数，
					但是还是会建立连接，再调用IocpAccept函数会直接关闭这个连接，
					然后造成一系列WSA函数的报错
			*/
			iocp.postAccept(&ioData);
		}
		_time_event.process_timer();
	}
	CELLLog_Info("EasyIOCPServer OnRun exit");
}

// 接收客户端连接
SOCKET EasyIOCPServer::IocpAccept(SOCKET cSock)
{
	// 在这里可以取出ip地址，做别的事情
	if (cSock == INVALID_SOCKET)
	{
		// 理论上不会触发
		CELLLog_pError("EasyIOCPServer IocpAccept error on line %d", __LINE__);
	}
	else
	{
		if (_clientCount < _nMaxClient)
		{
			AddClientToCELLServer(new CELLClient(cSock, _nSendBuffSize, _nRecvBuffSize));
		}
		else
		{
			CELLNetWork::destorySocket(cSock);
			CELLLog_Warning("IocpAccept to nMaxClient");
		}
	}
	return cSock;
}

#endif // #ifdef _WIN32
